#include "bullet.h"
#include "common.h"
#include "enemy.h"
#include "player.h"
#include "bullets/sinbullet.h"

#include "bullets/jiguang.h"
#include "bullets/laserbullet.h"

namespace fireplane
{
	Bullet::Bullet()
	{}

	Bullet::~Bullet()
	{}

	Bullet* Bullet::_createBullet(BulletCommand* cmd)
	{
		Bullet* ret = NULL;
		switch(cmd->_type){
		case BT_dir_bullet:
			{
				ret = new Bullet();

				CCAffineTransform tans = _all_bullets_parent->worldToNodeTransform();
				cmd->_pos = CCPointApplyAffineTransform(cmd->_pos,tans);
				cmd->_dir = CCPointApplyAffineTransform(cmd->_dir,tans);
				CCPoint org(0,0);
				org = CCPointApplyAffineTransform(org,tans);
				cmd->_dir.x = cmd->_dir.x - org.x;
				cmd->_dir.y = cmd->_dir.y - org.y;
				cmd->_dir = ccpNormalize(cmd->_dir);

				ret->init(cmd);
				ret->autorelease();

				ret->retain();
				_all_active_bullets.push_back(ret);
			}
			break;

		case BT_ji_guang:
			{
				ret = new JiGuangBullet();

				CCAffineTransform tans = _all_bullets_parent->worldToNodeTransform();
				cmd->_pos = CCPointApplyAffineTransform(cmd->_pos,tans);
				cmd->_dir = CCPointApplyAffineTransform(cmd->_dir,tans);
				CCPoint org(0,0);
				org = CCPointApplyAffineTransform(org,tans);
				cmd->_dir.x = cmd->_dir.x - org.x;
				cmd->_dir.y = cmd->_dir.y - org.y;
				cmd->_dir = ccpNormalize(cmd->_dir);

				ret->init(cmd);
				ret->autorelease();

				ret->retain();
				_all_active_bullets.push_back(ret);
			}
			break;

		case BT_sin_path_bullet:
			{
				ret = new SinBullet();

				CCAffineTransform tans = _all_bullets_parent->worldToNodeTransform();
				cmd->_pos = CCPointApplyAffineTransform(cmd->_pos,tans);

				cmd->_dir = Common::CCPointApplyAffineTransform(cmd->_dir,tans);
				cmd->_dir = ccpNormalize(cmd->_dir);

				ret->init(cmd);
				ret->autorelease();

				ret->retain();
				_all_active_bullets.push_back(ret);
			}
			break;

                   case BT_laser_bullet:
			{
				ret = new LaserBullet();

				CCAffineTransform tans = _all_bullets_parent->worldToNodeTransform();
				cmd->_pos = CCPointApplyAffineTransform(cmd->_pos,tans);

				cmd->_dir = Common::CCPointApplyAffineTransform(cmd->_dir,tans);
				cmd->_dir = ccpNormalize(cmd->_dir);

				ret->init(cmd);
				ret->autorelease();

				ret->retain();
				_all_active_bullets.push_back(ret);
			}
			break;
		}

		return ret;
	}

	bool Bullet::updateState( float dt )
	{
		if (isDestroy())
		{
			return false;
		}

		CCSize winSize = CCDirector::sharedDirector()->getWinSize();
		CCRect rect = CCRectMake(0,0,winSize.width,winSize.height);

		CCPoint pos = this->getPosition();
		CCPoint worldpos = this->getParent()->convertToWorldSpace(pos);

		if (rect.containsPoint(worldpos))
		{
			float moveX = _dir.x * _speed * dt;
			float moveY = _dir.y * _speed * dt;
			CCPoint move = ccp(moveX,moveY);

			pos.x += move.x;
			pos.y += move.y;
			this->setPosition(pos);
			return true;
		}
		else
		{
			// out of screen
			return false;
		}
	}

	void Bullet::destroy()
	{
		removeFromParentAndCleanup(true);
	}

	void Bullet::processCmd()
	{
		list<BulletCommand*>::iterator it = _all_commands.begin();
		list<BulletCommand*>::iterator itend = _all_commands.end();
		
		for (;it != itend;)
		{
			BulletCommand* bcmd = *it;
			_createBullet(bcmd);
			delete bcmd;
			it = _all_commands.erase(it);
		}
	}

	void Bullet::updateAllBullets( float dt )
	{
		processCmd();

		list<Bullet*>::iterator it = _all_active_bullets.begin();
		for (;it != _all_active_bullets.end();)
		{
			Bullet* bullet = *it;
			if (!bullet->updateState(dt))
			{
				bullet->destroy();
				bullet->release();
				it = _all_active_bullets.erase(it);
			}
			else
			{
				it++;
			}
		}
	}

	void Bullet::init(BulletCommand* cmd)
	{
		_body = (NULL);
		_lastZoneIdx = (-1);
		_currentZoneIdx = (-1);

		_speed = cmd->_speed;
		_dir = cmd->_dir;
		_owner = cmd->o;
		
		char buffer[0xff];
		switch(cmd->_img){
		case BI_img0:
			{
				sprintf(buffer,"%s","bullet/normalbullet.png");
			}
			break;

		case BI_img1:
			{
				sprintf(buffer,"%s","bullet/1_ZJ2_4_9.png");
			}
			break;

		case BI_img2:
			{
				sprintf(buffer,"%s","bullet/npc4/2.png");
			}
			break;

		case BI_img3:
			{
				sprintf(buffer,"%s","bullet/npc4/1.png");
			}

		case BI_img5:
			{
				sprintf(buffer,"%s","bullet/npc5/1.png");
			}
			break;


		case BI_img6:
			{
				sprintf(buffer,"%s","bullet/npc6/1.png");
			}
			break;

		case BI_img7:
			{
				sprintf(buffer,"%s","bullet/npc6/2.png");
			}
			break;


		case BI_img16:
			{
				sprintf(buffer,"%s","bullet/npc1/0.png");
			}
			break;
	    
		case BI_img17:
		{
			sprintf(buffer,"%s","bullet/npc2/0.png");
		}
			break;

		case BI_img18:
			{
				sprintf(buffer,"%s","bullet/npc3/0.png");
			}
			break;
		}

		_body = CCSprite::create(buffer);
		float degree = CC_RADIANS_TO_DEGREES(acos(ccpDot(_dir,ccp(0,1))));

		if (ccpCross(_dir,ccp(0,1)) < 0)
		{
			degree = 360 - degree;
		}

		_body->setRotation(degree);
		_all_bullets_parent->addChild(this);
		this->addChild(_body);
		this->setPosition(cmd->_pos);
	}

	void Bullet::initBulletManager( CCNode* parent )
	{
		_all_bullets_parent = parent;
	}

	void Bullet::destroyBulletManager()
	{
	}

	void Bullet::pushCommand(BulletCommand* cmd)
	{
		_all_commands.push_back(cmd);
	}

	bool Bullet::isCollision2SceneObject(SceneObjectBase* sceneobject){
		CCPoint scenobjectPos = sceneobject->getPosition();
		CCRect rect = sceneobject->getCollisionRect();
		
		CCNode* sceneObjectParent = sceneobject->getSceneObjectParent();
		CCPoint bulletPos = this->getPosition();
		bulletPos = this->getParent()->convertToWorldSpace(bulletPos);
		bulletPos = sceneObjectParent->convertToNodeSpace(bulletPos);

		bool flag = rect.containsPoint(bulletPos);

		if (flag){
			return true;
		}

		return false;
	}

	bool Bullet::isCollision2Player(Player* player){
		CCRect rect = player->getPlayerWorldCollisionSize();
		CCAffineTransform tan = this->getParent()->worldToNodeTransform();

		rect = CCRectApplyAffineTransform(rect,tan);
		CCPoint pos = this->getPosition();

		if(rect.containsPoint(pos)){
			return true;
		}

		return false;
	}

	bool Bullet::isCollision2Eneny( Enemy* enemy )
	{
		CCPoint enemyPos = enemy->getPosition();

		list<CCRect>& all_collision_rect = enemy->getCollisionRect();
		list<CCRect>::iterator it = all_collision_rect.begin();
		for (;it != all_collision_rect.end();it++)
		{
			CCRect& rect = *it;
			bool flag = rect.containsPoint(this->getPosition());

			if (flag)
			{
				return true;
			}
		}

		return false;
	}

	void Bullet::onAttack()
	{
		setDestroyFlag(true);
	}

	CCPoint Bullet::getWorldPos()
	{
		CCPoint pos = this->getPosition();
		pos = this->getParent()->convertToWorldSpace(pos);

		return pos;
	}

	list<Bullet::BulletCommand*> Bullet::_all_commands;
	list<Bullet*> Bullet::_all_active_bullets;
	CCNode* Bullet::_all_bullets_parent = NULL;
}